home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / lisp / elk-2_0.lha / elk-2.0 / src / dump.elf.c < prev    next >
C/C++ Source or Header  |  1992-10-21  |  9KB  |  256 lines

  1. /* Derived from the file src/unexelf.c written by Spencer W. Thomas
  2.  * (from the Emacs 18.58 distribution), to which the following copyright
  3.  * applies:
  4.  *
  5.  *   Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
  6.  *
  7.  *    This program is free software; you can redistribute it and/or modify
  8.  *    it under the terms of the GNU General Public License as published by
  9.  *    the Free Software Foundation; either version 1, or (at your option)
  10.  *    any later version.
  11.  *
  12.  *    This program is distributed in the hope that it will be useful,
  13.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *    GNU General Public License for more details.
  16.  *
  17.  *    You should have received a copy of the GNU General Public License
  18.  *    along with this program; if not, write to the Free Software
  19.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  *
  21.  *  In other words, you are welcome to use, share and improve this program.
  22.  *  You are forbidden to forbid anyone else to use, share and improve
  23.  *  what you give them.   Help stamp out software-hoarding!
  24.  */
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <memory.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include <fcntl.h>
  31. #include <elf.h>
  32. #include <sys/mman.h>
  33.  
  34. /* Get the address of a particular section or program header entry,
  35.  * accounting for the size of the entries.
  36.  */
  37. #define OLD_SECTION_H(n) \
  38.      (*(Elf32_Shdr *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))
  39. #define NEW_SECTION_H(n) \
  40.      (*(Elf32_Shdr *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))
  41. #define OLD_PROGRAM_H(n) \
  42.      (*(Elf32_Phdr *) ((byte *) old_program_h + old_file_h->e_phentsize * (n)))
  43. #define NEW_PROGRAM_H(n) \
  44.      (*(Elf32_Phdr *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))
  45.  
  46. typedef unsigned char byte;
  47.  
  48. static int round_up (x, y) int x, y; {
  49.     int rem = x % y;
  50.  
  51.     if (rem == 0)
  52.     return x;
  53.     return x - rem + y;
  54. }
  55.  
  56. Object P_Dump (ofile) Object ofile; {
  57.     unsigned int bss_end;
  58.     int new_file_size;
  59.     caddr_t old_base, new_base;
  60.     /* Pointers to the file, program and section headers for the old and new
  61.      * files.
  62.      */
  63.     Elf32_Ehdr *old_file_h, *new_file_h;
  64.     Elf32_Phdr *old_program_h, *new_program_h;
  65.     Elf32_Shdr *old_section_h, *new_section_h;
  66.     /* Point to the section name table in the old file.
  67.      */
  68.     char *old_section_names;
  69.     Elf32_Addr old_bss_addr, new_bss_addr;
  70.     Elf32_Word old_bss_size, new_data2_size;
  71.     Elf32_Off  new_data2_offset;
  72.     Elf32_Addr new_data2_addr;
  73.     int n, old_bss_index, old_data_index, new_data2_index;
  74.     struct stat stat_buf;
  75.  
  76.     Dump_Prolog;
  77.  
  78.     Was_Dumped = 1;
  79.  
  80.     if (fstat (afd, &stat_buf) == -1) {
  81.     Dump_Finalize;
  82.     Primitive_Error ("cannot stat old a.out file: ~E");
  83.     }
  84.     old_base = mmap (0, stat_buf.st_size, PROT_READ, MAP_SHARED, afd, 0);
  85.     if (old_base == (caddr_t)-1) {
  86.     Dump_Finalize;
  87.     Primitive_Error ("cannot mmap old a.out file: ~E");
  88.     }
  89.     /* Get pointers to headers & section names.
  90.      */
  91.     old_file_h = (Elf32_Ehdr *) old_base;
  92.     old_program_h = (Elf32_Phdr *) ((byte *) old_base + old_file_h->e_phoff);
  93.     old_section_h = (Elf32_Shdr *) ((byte *) old_base + old_file_h->e_shoff);
  94.     old_section_names = (char *) old_base
  95.     + OLD_SECTION_H(old_file_h->e_shstrndx).sh_offset;
  96.  
  97.     /* Find the old .bss section.  Figure out parameters of the new
  98.      * data2 and bss sections.
  99.      */
  100.     for (old_bss_index = 1; old_bss_index < old_file_h->e_shnum;
  101.                 old_bss_index++) {
  102.     if (strcmp (old_section_names + OLD_SECTION_H(old_bss_index).sh_name,
  103.         ".bss") == 0)
  104.         break;
  105.     }
  106.     if (old_bss_index == old_file_h->e_shnum) {
  107.     Dump_Finalize;
  108.     Primitive_Error ("cannot find .bss in old a.out file");
  109.     }
  110.     old_bss_addr = OLD_SECTION_H(old_bss_index).sh_addr;
  111.     old_bss_size = OLD_SECTION_H(old_bss_index).sh_size;
  112.     new_bss_addr = (Elf32_Addr)sbrk (0);
  113.     new_data2_addr = old_bss_addr;
  114.     new_data2_size = new_bss_addr - old_bss_addr;
  115.     new_data2_offset = OLD_SECTION_H(old_bss_index).sh_offset;
  116.  
  117.     if ((unsigned) new_bss_addr < (unsigned) old_bss_addr + old_bss_size) {
  118.     Dump_Finalize;
  119.     Primitive_Error (".bss shrank");
  120.     }
  121.     /* Set the output file to the right size and mmap(2) it.  Set
  122.      * pointers to various interesting objects.  stat_buf still has
  123.      * old_file data.
  124.      */
  125.     new_file_size = stat_buf.st_size + old_file_h->e_shentsize + new_data2_size;
  126.     if (ftruncate (ofd, new_file_size) == -1) {
  127.     Dump_Finalize;
  128.     Primitive_Error ("cannot ftruncate new a.out file: ~E");
  129.     }
  130.     new_base = mmap (0, new_file_size, PROT_READ | PROT_WRITE, MAP_SHARED,
  131.     ofd, 0);
  132.     if (new_base == (caddr_t)-1) {
  133.     Dump_Finalize;
  134.     Primitive_Error ("cannot mmap new a.out file: ~E");
  135.     }
  136.     new_file_h = (Elf32_Ehdr *) new_base;
  137.     new_program_h = (Elf32_Phdr *) ((byte *) new_base + old_file_h->e_phoff);
  138.     new_section_h = (Elf32_Shdr *)
  139.     ((byte *) new_base + old_file_h->e_shoff + new_data2_size);
  140.  
  141.     /* Make our new file, program and section headers as copies of the
  142.      * originals.
  143.      */
  144.     memcpy (new_file_h, old_file_h, old_file_h->e_ehsize);
  145.     memcpy (new_program_h, old_program_h,
  146.     old_file_h->e_phnum * old_file_h->e_phentsize);
  147.     memcpy (new_section_h, old_section_h,
  148.     old_file_h->e_shnum * old_file_h->e_shentsize);
  149.  
  150.     /* Fix up file header.  We'll add one section.  Section header is
  151.      * further away now.
  152.      */
  153.     new_file_h->e_shoff += new_data2_size;
  154.     new_file_h->e_shnum += 1;
  155.  
  156.     /* Fix up a new program header.  Extend the writable data segment so
  157.      * that the bss area is covered too. Find that segment by looking
  158.      * for a segment that ends just before the .bss area.  Make sure
  159.      * that no segments are above the new .data2.  Put a loop at the end
  160.      * to adjust the offset and address of any segment that is above
  161.      * data2, just in case we decide to allow this later.
  162.      */
  163.     for (n = new_file_h->e_phnum - 1; n >= 0; n--) {
  164.     /* Compute maximum of all requirements for alignment of section.
  165.      */
  166.     int alignment = (NEW_PROGRAM_H (n)).p_align;
  167.  
  168.     if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment)
  169.         alignment = OLD_SECTION_H (old_bss_index).sh_addralign;
  170.     if (NEW_PROGRAM_H(n).p_vaddr + NEW_PROGRAM_H(n).p_filesz
  171.         > old_bss_addr) {
  172.         Dump_Finalize;
  173.         Primitive_Error ("program segment above .bss");
  174.     }
  175.     if (NEW_PROGRAM_H(n).p_type == PT_LOAD
  176.         && (round_up ((NEW_PROGRAM_H (n)).p_vaddr
  177.             + (NEW_PROGRAM_H (n)).p_filesz, alignment)
  178.             == round_up (old_bss_addr, alignment)))
  179.         break;
  180.     }
  181.     if (n < 0) {
  182.     Dump_Finalize;
  183.     Primitive_Error ("cannot find segment next to .bss");
  184.     }
  185.     NEW_PROGRAM_H(n).p_filesz += new_data2_size;
  186.     NEW_PROGRAM_H(n).p_memsz = NEW_PROGRAM_H(n).p_filesz;
  187.  
  188. #if 0 /* Maybe allow section after data2 - does this ever happen? */
  189.     for (n = new_file_h->e_phnum - 1; n >= 0; n--) {
  190.     if (NEW_PROGRAM_H(n).p_vaddr
  191.         && NEW_PROGRAM_H(n).p_vaddr >= new_data2_addr)
  192.         NEW_PROGRAM_H(n).p_vaddr += new_data2_size - old_bss_size;
  193.     if (NEW_PROGRAM_H(n).p_offset >= new_data2_offset)
  194.         NEW_PROGRAM_H(n).p_offset += new_data2_size;
  195.     }
  196. #endif
  197.     /* Fix up section headers based on new .data2 section.  Any section
  198.      * whose offset or virtual address is after the new .data2 section
  199.      * gets its value adjusted.  .bss size becomes zero and new address
  200.      * is set.  data2 section header gets added by copying the existing
  201.      * .data header and modifying the offset, address and size.
  202.      */
  203.     for (n = 1; n < new_file_h->e_shnum; n++) {
  204.     if (NEW_SECTION_H(n).sh_offset >= new_data2_offset)
  205.         NEW_SECTION_H(n).sh_offset += new_data2_size;
  206.     if (NEW_SECTION_H(n).sh_addr
  207.         && NEW_SECTION_H(n).sh_addr >= new_data2_addr)
  208.     NEW_SECTION_H(n).sh_addr += new_data2_size - old_bss_size;
  209.     }
  210.     new_data2_index = old_file_h->e_shnum;
  211.  
  212.     for (old_data_index = 1; old_data_index < old_file_h->e_shnum;
  213.                  old_data_index++)
  214.     if (strcmp (old_section_names + OLD_SECTION_H(old_data_index).sh_name,
  215.         ".data") == 0)
  216.         break;
  217.     if (old_data_index == old_file_h->e_shnum) {
  218.     Dump_Finalize;
  219.     Primitive_Error ("cannot find .data");
  220.     }
  221.     memcpy (&NEW_SECTION_H(new_data2_index), &OLD_SECTION_H(old_data_index),
  222.     new_file_h->e_shentsize);
  223.  
  224.     NEW_SECTION_H(new_data2_index).sh_addr = new_data2_addr;
  225.     NEW_SECTION_H(new_data2_index).sh_offset = new_data2_offset;
  226.     NEW_SECTION_H(new_data2_index).sh_size = new_data2_size;
  227.  
  228.     NEW_SECTION_H(old_bss_index).sh_size = 0;
  229.     NEW_SECTION_H(old_bss_index).sh_addr = new_data2_addr + new_data2_size;
  230.  
  231.     /* Write out the sections. .data and .data1 (and data2, called
  232.      * ".data" in the strings table) get copied from the current process
  233.      * instead of the old file.
  234.      */
  235.     for (n = new_file_h->e_shnum - 1; n; n--) {
  236.     caddr_t src;
  237.  
  238.     if (NEW_SECTION_H(n).sh_type == SHT_NULL
  239.         || NEW_SECTION_H(n).sh_type == SHT_NOBITS)
  240.     continue;
  241.  
  242.     if (strcmp (old_section_names + NEW_SECTION_H(n).sh_name,
  243.         ".data") == 0 ||
  244.         strcmp ((old_section_names + NEW_SECTION_H(n).sh_name),
  245.         ".data1") == 0)
  246.         src = (caddr_t) NEW_SECTION_H(n).sh_addr;
  247.     else
  248.         src = old_base + OLD_SECTION_H(n).sh_offset;
  249.  
  250.     memcpy (NEW_SECTION_H(n).sh_offset + new_base, src,
  251.         NEW_SECTION_H(n).sh_size);
  252.     }
  253.  
  254.     Dump_Epilog;
  255. }
  256.